#include "log.h"
#include <map>

namespace xyts {

std::map<std::string, quill::LogLevel> log_level_map = {
    {"trace", quill::LogLevel::TraceL3}, {"debug", quill::LogLevel::Debug},
    {"info", quill::LogLevel::Info},     {"warning", quill::LogLevel::Warning},
    {"error", quill::LogLevel::Error},   {"fatal", quill::LogLevel::Critical}};

XyGlobalLogger::XyGlobalLogger() : logger_(nullptr) {}

XyGlobalLogger::~XyGlobalLogger() {
  // Destroy the logger
  if (logger_) {
    logger_.reset();
  }
}

void XyGlobalLogger::Init(const std::string &logfile,
                          const std::string &loglevel) {
  // Configure Quill global logging system
  quill::configure([]() {
    quill::Config cfg;
    return cfg;
  }());

  // Get log level
  auto it = log_level_map.find(loglevel);
  if (it == log_level_map.end()) {
    it = log_level_map.find("info"); // Default to info level
  }

  // Create file handler
  auto file_handler = quill::file_handler(logfile, []() {
    quill::FileHandlerConfig cfg;
    cfg.set_open_mode('w');
    cfg.set_pattern("[%(time)] [%(thread_id)] [%(file_name):%(line_number)] "
                    "[%(logger)] [%(log_level)] - %(message)",
                    "%H:%M:%S.%Qms");
    return cfg;
  }());

  // Create logger using the handler
  auto logger = quill::create_logger(logfile, {file_handler});
  logger->set_log_level(it->second);

  // Assign the created logger to the class member
  logger_ = std::make_unique<XyLogger>(logger);

  // Start Quill logging system
  quill::start();
}

bool XyGlobalLogger::set_log_level(const std::string &loglevel) {
  auto it = log_level_map.find(loglevel);
  if (it == log_level_map.end()) {
    return false;
  }

  if (logger_) {
    logger_->logger()->set_log_level(it->second);
    return true;
  }

  return false;
}

std::string XyGlobalLogger::log_level() const {
  if (!logger_) {
    return "none";
  }

  for (const auto &pair : log_level_map) {
    if (pair.second == logger_->logger()->log_level()) {
      return pair.first;
    }
  }

  return "unknown";
}

void InitGlobalLogger(const std::string &logfile, const std::string &loglevel) {
  XyGlobalLogger::Instance().Init(logfile, loglevel);
}

void FlushLog() { quill::flush(); }

std::shared_ptr<XyLogger> GetCustomLogger(const std::string &logger_name,
                                          const std::string &logfile,
                                          const std::string &loglevel,
                                          const std::string &pattern) {
  auto it = log_level_map.find(loglevel);
  if (it == log_level_map.end()) {
    return nullptr;
  }

  auto file_handler = quill::file_handler(logfile, [pattern]() {
    quill::FileHandlerConfig cfg;
    cfg.set_open_mode('w');
    cfg.set_pattern(pattern, "%H:%M:%S.%Qms");
    return cfg;
  }());

  auto logger = quill::create_logger(logger_name, {file_handler});
  logger->set_log_level(it->second);

  return std::make_shared<XyLogger>(logger);
}

} // namespace xyts